/*
 *
 *
Copyright (c) 1998-2001 Aristar, Inc. All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

3. The end-user documentation included with the redistribution, if any,
must include the following acknowledgment:

"This product includes software developed by Aristar, Inc. (http://www.aristar.com/)."

Alternately, this acknowledgment may appear in the software itself, if and
wherever such third-party acknowledgments normally appear.

4. The names "Dialect" and "Aristar, Inc." must not be used to endorse or
promote products derived from this software without prior written permission.
For written permission, please contact info@aristar.com.

5. Products derived from this software may not be called "Dialect", nor may
"Dialect" appear in their name, without prior written permission of Aristar, Inc.

THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
ARISTAR, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

This software consists of voluntary contributions made by many individuals
on behalf of Aristar, Inc.  For more information on Aristar, Inc.,
please see <http://www.aristar.com/>.

Portions of this software are based upon software freely available and
written by individuals not associated with Aristar, Inc.  Copyrights are
maintained in the relevant source code files.
 *
 *
 */

#ifndef __CDEBUG__H___
#define __CDEBUG__H___

//
//	This file is included by DConfigGlobals.h
//

#include "DTCHAR.h"

//==============================================================

#if defined(__WINNT__) || defined(__WINCE__)
#	ifdef USING_MFC
#		include <afxwin.h>
#	else
#		include <windows.h>
#	endif
#endif

#ifdef __WINCE__
#	define USE_SEH	// CE doesn't support C++ exceptions yet
#endif

//==============================================================
void SyntaxError(LPCTSTR parmString, ...);
void RunTimeError(LPCTSTR parmString, ...);
void InternalError(LPCTSTR parmString, ...);
//==============================================================

class EException {
public:
	EException(LPCTSTR _module = NULL, int _line = 0, DWORD exceptCode = 0xEFFFFFFF, LPCTSTR msg = NULL);
	EException(const EException& copy);
	EException& operator = (const EException& copy);
	~EException();
	void SetStrings(LPCTSTR mod, LPCTSTR msg);
	DWORD exceptionCode;
	TCHAR* message;
	TCHAR* module;
	int line;
};

//===============================================================================

#ifndef USING_MFC			// MFC defines the ASSERT macro for us
#	ifdef __WINCE__
#		define ASSERT(x)	// We need to make a replacement someday
#	else
#		include <assert.h>
#		define ASSERT(x) assert(x)
#	endif
#endif

//===============================================================================
// The current CE compilers support only Win32 Structured Exception Handling (SEH)
// as opposed to the C++ standard available under NT and 95 (as well as gcc 2.8.x)
// The biggest important difference between SEH and C++ exception handling is that
// SEH isn't object aware, that is, when unwinding the stack SEH will not call
// an objects destructor (leaving the potentially for massive memory leaks).


// Here we create our own exceptions to throw in SEH
// We'll use them for our error codes even when not using SEH
// As defined in <winerror.h>
//		Severity codes:
//          0 - Success			// ???
//          1 - Informational
//          2 - Warning
//          3 - Error
//

#ifndef FACILITY_NULL
#	define FACILITY_NULL	0
#endif

#define SEH_EXCEPTION(severity, facility, exception)	\
		((DWORD)((severity << 30) | (1 << 29) | (0 << 28) | (facility << 16) | (exception)))

#define EXCEPTION_SYNTAX		SEH_EXCEPTION(3, FACILITY_NULL, 30)
#define EXCEPTION_RUNTIME		SEH_EXCEPTION(3, FACILITY_NULL, 40)
#define EXCEPTION_INTERPRETER	SEH_EXCEPTION(3, FACILITY_NULL, 50)

#ifdef USE_SEH	// We are using Win32 structured exception handling
				// To use SEH, specify compiler option /GX-
#	pragma warning(once:4509)	// Display this warning only once, just to remind us
struct exceptionStuff {
	DWORD exceptionCode;
	LPTSTR message;
	exceptionStuff():exceptionCode(0xEFFFFFFF),message(NULL){};
	~exceptionStuff(){if (message) delete[] message;};
	void Set(DWORD code, LPCTSTR msg) {
		exceptionCode = code;
		if (message) delete[] message;
		int length = _tcslen(msg);
		if (length <= 0) message = NULL;
		else {
			message = new TCHAR[length + 1];
			_tcscpy(message, msg);
		}
	}
};
static exceptionStuff _excStuff;
//#	define	_TRY						EException exc; __try
#	define	_TRY						DWORD _code = 0; LPCTSTR _msg = NULL; __try
#	define CE_TRY						__try
#	define CE_FINALLY					__finally
#	define RAISE_SYNTAX(err, m, l)		_excStuff.Set(EXCEPTION_SYNTAX, err), RaiseException(EXCEPTION_SYNTAX, EXCEPTION_NONCONTINUABLE, 2, (LPDWORD)&_excStuff)//new EException(m, l, EXCEPTION_SYNTAX, err))
#	define RAISE_RUNTIME(err, m, l)		_excStuff.Set(EXCEPTION_RUNTIME, err), RaiseException(EXCEPTION_RUNTIME, EXCEPTION_NONCONTINUABLE, 2, (LPDWORD)&_excStuff)//new EException(m, l, EXCEPTION_RUNTIME, err))
#	define RAISE_INTERPRETER(err, m, l)	_excStuff.Set(EXCEPTION_INTERPRETER, err), RaiseException(EXCEPTION_INTERPRETER, EXCEPTION_NONCONTINUABLE, 2, (LPDWORD)&_excStuff)//new EException(m, l, EXCEPTION_INTERPRETER, err))
#	define CE_CLEANUP1(a)				if (AbnormalTermination()) a
#	define CE_CLEANUP2(a, b)			if (AbnormalTermination()) a, b
#	define CE_CLEANUP3(a, b, c)			if (AbnormalTermination()) a, b, c
#	define CE_CLEANUP4(a, b, c, d)		if (AbnormalTermination()) a, b, c, d
#	define CE_CLEANUP5(a, b, c, d, e)	if (AbnormalTermination()) a, b, c, d, e
//#	define SET_EXC
#	define SET_EXC				_code = (GetExceptionInformation())->ExceptionRecord->ExceptionInformation[0], \
								_msg = (LPCTSTR)(GetExceptionInformation())->ExceptionRecord->ExceptionInformation[1]
#	define _CATCH_SYNTAX		__except((GetExceptionCode() == EXCEPTION_SYNTAX) ? SET_EXC, EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
#	define _CATCH_RUNTIME		__except((GetExceptionCode() == EXCEPTION_RUNTIME) ? SET_EXC, EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
#	define _CATCH_INTERPRETER	__except((GetExceptionCode() == EXCEPTION_INTERPRETER) ? SET_EXC, EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
#	define _CATCH_ALL			__except(EXCEPTION_EXECUTE_HANDLER)
#	define _CATCH_EXCEPTION		__except(SET_EXC, EXCEPTION_EXECUTE_HANDLER)
//#	define _CATCH_EXCEPTION		__except(EXCEPTION_EXECUTE_HANDLER)
#	define GET_EXCEPTION_INFO	EException exc(NULL, 0, _code, _msg);
#	define GET_EXC_MESSAGE		_msg
#	define GET_EXC_CODE			_code
#else // !USE_SEH ///////////////////////////////////////////////////////////////
      // We are using C++ exception handling
#	define	_TRY						try
#	define CE_TRY						// Not used
#	define CE_FINALLY					// Not used
#	define RAISE_SYNTAX(err, m, l)		throw EException(m, l, EXCEPTION_SYNTAX, err)
#	define RAISE_RUNTIME(err, m, l)		throw EException(m, l, EXCEPTION_RUNTIME, err)
#	define RAISE_INTERPRETER(err, m, l)	throw EException(m, l, EXCEPTION_INTERPRETER, err)
#	define CE_CLEANUP1(a)				// Not used
#	define CE_CLEANUP2(a, b)			// Not used
#	define CE_CLEANUP3(a, b, c)			// Not used
#	define CE_CLEANUP4(a, b, c, d)		// Not used
#	define CE_CLEANUP5(a, b, c, d, e)	// Not used
#	define _CATCH_ALL					catch(...)
#	define _CATCH_EXCEPTION				catch(EException exc)
#	define GET_EXCEPTION_INFO			// Not used
#	define GET_EXC_MESSAGE				exc.message
#	define GET_EXC_CODE					exc.exceptionCode
#endif	// USE_SEH
//===============================================================================

/*
 *	Here is an example of how to use the previous exception handling macros
 *	in a cross-platformable way.
 *
class t {
public:
	t(char* str):s(str){printf("In constructor - %s\n\n", str);};
	~t(){printf("In destructor - %s\n\n", s);};
	char* s;
};

void func(t arg)
{
	int z, y = 0;

	CE_TRY {
		printf("In func()\n\n");
		z = 5 / y;	// Cause an exception
	}
	CE_FINALLY {
		// We also need to cleanup objects passed as arguments
		// This is only with objects copied by value, not reference and pointers
		CE_CLEANUP1(arg.~t());
	}
}

void main()
{
	t x1("x1");
	t* x2 = new t("x2");
	t x3("x3");

	CE_TRY {
		_TRY {
			func(t("x4"));
			printf("In try\n\n");
		}
		_CATCH_RETURN {
			printf("In exception handler\n\n");
		}
	}
	CE_FINALLY {
		CE_CLEANUP2(x1.~t(), x3.~t());
		delete x2;	// The usual delete done here
	}
}*/

//===================================================
#endif	// __CDEBUG__H___
